#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gevent import monkey
monkey.patch_socket()
from gevent import Greenlet
import ConfigFileData
import logging
import time
import socket
import ThreadSafeSingletion
import SocketTools
import RTS3_pb2
from pageType import *
import base_pb2
import IL.DataSource.Market



import Singleton

@Singleton.singleton
class RTS3_Stock(Greenlet):
    def __init__(self):
        Greenlet.__init__(self)
        self.requesetId = 0
        self.config = ConfigFileData.Data()
        self.packTools = SocketTools.StructProtocol()
        self.queue = ThreadSafeSingletion.SafeQueue()
        self.RebuildConnection()
        self.LOG_CURR_TIME = time.clock()
        self.LOG_NEXT_TIME = int(self.config.get(u"Start.LogTimeInterval")) + int(self.LOG_CURR_TIME)
        self.SignalFlag = False
        self.signalDict = {}
        self.marketSource = IL.DataSource.Market.MarketSource()

    def RebuildConnection(self):
        while True:
            try:
                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.sock.settimeout(5)
                self.sock.connect((self.config.get(u'market.RTS3Stock.ip'), self.config.get(u'market.RTS3Stock.port')))

            except:
                logging.warning(u"Market-Stock:Socket连接失败, 等待5秒后重新尝试...")
                time.sleep(5)
                continue

            try:
                # 忽略连接成功后的市场代码
                header = self.Recv(self.packTools.getHeaderLen())
                self.Recv(self.packTools.GetBodyLen(header))
            except:
                pass

            try:
                self.UpdateCodeTable()
            except:
                logging.warning(u"与RTS3_Stock接口初次交互的时候，发生错误。重新连接并且尝试！")
                continue
            break

    def run(self):
        print u"[Start]Market-Stock"
        switch = {
            LYMK_CODETABLE_ADD: self.UpdateCodeTable,
            LYMK_HEARTBEAT_REQ: self.Heart,
            LYMK_MARKETDATA: self.HandleMarket,
            LYMK_CODETABLE_RESP: self.HandleCodeTable,
            LYMK_CODETABLE_CHANGE: self.RequestCodeTable
        }
        while True:
            self.LOG_CURR_TIME = int(time.clock())
            if int(self.LOG_CURR_TIME) > int(self.LOG_NEXT_TIME):
                self.Heart()
                self.LOG_NEXT_TIME = int(self.config.get(u"Start.LogTimeInterval")) + int(self.LOG_CURR_TIME)

            try:
                header = self.Recv(self.packTools.getHeaderLen())
                body = self.Recv(self.packTools.GetBodyLen(header))
                self.packTools.putData(header+body)
            except socket.error, e:
                if e.errno:
                    logging.warning(u"RTS3-Stock.recv 发生错误:{0}, 重新建立连接...".format(e))
                    self.RebuildConnection()
                continue
            except:
                logging.warning(u"RTS3-Stock:_run:发生未知错误。")
                exit(-1)

            while 1:
                data = self.packTools.getOnce()
                if data:
                    pType = data['head'][2]
                    try:
                        switch[int(pType)](message=data)
                    except:
                        logging.warning(u"RTS3-Stock处理行情包子类型：{0} 发生错误。".format(pType))
                else:
                    break

    def RequestCodeTable(self, **kwargs):
        message = kwargs['message']
        resp = RTS3_pb2.CodeTableChange()
        resp.ParseFromString(message['body'])
        self.CodeTableRequest(resp.exchid_flag)

    def OpenSignal(self):
        self.SignalFlag = True

    def CloseSignal(self):
        self.SignalFlag = False

    # speID 特征码
    def add_Signal(self, code, signalFunc, speID):
        if self.signalDict.get(code, None) is None:
            self.signalDict[code] = dict()
        self.signalDict[code][speID] = signalFunc

    def del_Signal(self, code, speID):
        try:
            self.signalDict[code].pop(speID)
        except:
            pass

    def CodeTableRequest(self, code):
        req = RTS3_pb2.CodeTableReq()
        req.exchid_flag = code
        req = req.SerializeToString()
        data = self.packTools.pack([len(req), base_pb2.SYS_QUOTATION, 0x0200, self.RequesetId()], req)
        self.sock.sendall(data)

    def Recv(self, Packlen):
        ret = str()
        while 1:
            recvBuf = self.sock.recv(Packlen-len(ret))
            if len(recvBuf) == Packlen-len(ret):
                ret += recvBuf
                break
            ret += recvBuf
        return ret

    def SubMarketRequest(self, sub):
        req = RTS3_pb2.MarketDataReqByMdType()
        req.sub_type = 1
        req.mk_type = sub
        req = req.SerializeToString()
        data = self.packTools.pack([len(req), base_pb2.SYS_QUOTATION, 0x0100, self.RequesetId()], req)
        self.sock.sendall(data)


    def Heart(self, **kwargs):
        data = self.packTools.pack([0, base_pb2.SYS_QUOTATION, base_pb2.CMD_HEARTBEAT_RESP, self.RequesetId()], '')
        self.sock.sendall(data)

    def UpdateCodeTable(self, **kwargs):
        self.CodeTableRequest(0)
        self.CodeTableRequest(1)
        self.SubMarketRequest(LYMK_MARKETDATA)


    def HandleCodeTable(self, **kwargs):
        message = kwargs['message']
        resp = RTS3_pb2.SecurityCodeResp()
        resp.ParseFromString(message['body'])
        self.queue.put([u'StockCodeTable', resp, kwargs['message']['head'][3]])

    def HandleMarket(self, **kwargs):
        message = kwargs['message']['body']
        market = RTS3_pb2.MarketData()
        market.ParseFromString(message)
        self.queue.put([u'StockMarket', market, kwargs['message']['head'][3]])
        if self.SignalFlag:
            code = self.marketSource.get_code_by_id(market.idnum)
            if code and self.signalDict.get(code, None):
                for function in self.signalDict[code].values():
                    function()

    def RequesetId(self):
        self.requesetId += 1
        return str(self.requesetId)

@Singleton.singleton
class RTS3_Future(Greenlet):
    def __init__(self):
        Greenlet.__init__(self)
        self.requesetId = 0
        self.config = ConfigFileData.Data()
        self.packTools = SocketTools.StructProtocol()
        self.queue = ThreadSafeSingletion.SafeQueue()
        self.RebuildConnection()
        self.LOG_CURR_TIME = time.clock()
        self.LOG_NEXT_TIME = int(self.config.get(u"Start.LogTimeInterval")) + int(self.LOG_CURR_TIME)
        self.SignalFlag = False
        self.signalDict = {}
        self.marketSource = IL.DataSource.Market.MarketSource()

    def RebuildConnection(self):
        while True:
            try:
                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.sock.settimeout(5)
                self.sock.connect((self.config.get(u'market.RTS3Futures.ip'), self.config.get(u'market.RTS3Futures.port')))

            except:
                logging.warning(u"Market-Futures:Socket连接失败, 等待5秒后重新尝试...")
                time.sleep(5)
                continue

            try:
                # 忽略连接成功后的市场代码
                header = self.Recv(self.packTools.getHeaderLen())
                self.Recv(self.packTools.GetBodyLen(header))
            except:
                pass

            try:
                self.UpdateCodeTable()
            except:
                logging.warning(u"与Futures接口初次交互的时候，发生错误。重新连接并且尝试！")
                continue
            break

    def run(self):
        print u"[Start]Market-Futures"
        switch = {
            LYMK_CODETABLE_ADD: self.UpdateCodeTable,
            LYMK_HEARTBEAT_REQ: self.Heart,
            LYMK_CODETABLE_RESP: self.HandleCodeTable,
            LYMK_FUTURE: self.HandleFutures,
            LYMK_CODETABLE_CHANGE: self.RequestCodeTable
        }
        while True:
            self.LOG_CURR_TIME = int(time.clock())
            if int(self.LOG_CURR_TIME) > int(self.LOG_NEXT_TIME):
                self.Heart()
                self.LOG_NEXT_TIME = int(self.config.get(u"Start.LogTimeInterval")) + int(self.LOG_CURR_TIME)



            try:
                header = self.Recv(self.packTools.getHeaderLen())
                body = self.Recv(self.packTools.GetBodyLen(header))
                self.packTools.putData(header+body)
            except socket.error, e:
                if e.errno:
                    logging.warning(u"Futures.recv 发生错误:{0}, 重新建立连接...".format(e))
                    self.RebuildConnection()
                continue
            except:
                logging.warning(u"Futures:_run:发生未知错误。")
                exit(-1)

            while 1:
                data = self.packTools.getOnce()
                if data:
                    pType = data['head'][2]
                    try:
                        switch[int(pType)](message=data)
                    except:
                        logging.warning(u"Futures处理行情包子类型：{0} 发生错误。".format(pType))
                else:
                    break

    def RequestCodeTable(self, **kwargs):
        message = kwargs['message']
        resp = RTS3_pb2.CodeTableChange()
        resp.ParseFromString(message['body'])
        self.CodeTableRequest(resp.exchid_flag)

    def OpenSignal(self):
        self.SignalFlag = True

    def CloseSignal(self):
        self.SignalFlag = False

    # speID 特征码
    def add_Signal(self, code, signalFunc, speID):
        if self.signalDict.get(code, None) is None:
            self.signalDict[code] = dict()
        self.signalDict[code][speID] = signalFunc

    def del_Signal(self, code, speID):
        try:
            self.signalDict[code].pop(speID)
        except:
            pass

    def CodeTableRequest(self, code):
        req = RTS3_pb2.CodeTableReq()
        req.exchid_flag = code
        req = req.SerializeToString()
        data = self.packTools.pack([len(req), base_pb2.SYS_QUOTATION, 0x0200, self.RequesetId()], req)
        self.sock.sendall(data)

    def Recv(self, Packlen):
        ret = str()
        while 1:
            recvBuf = self.sock.recv(Packlen-len(ret))
            if len(recvBuf) == Packlen-len(ret):
                ret += recvBuf
                break
            ret += recvBuf
        return ret

    def SubMarketRequest(self, sub):
        req = RTS3_pb2.MarketDataReqByMdType()
        req.sub_type = 1
        req.mk_type = sub
        req = req.SerializeToString()
        data = self.packTools.pack([len(req), base_pb2.SYS_QUOTATION, 0x0100, self.RequesetId()], req)
        self.sock.sendall(data)

    def Heart(self, **kwargs):
        data = self.packTools.pack([0, base_pb2.SYS_QUOTATION, base_pb2.CMD_HEARTBEAT_RESP, self.RequesetId()], '')
        self.sock.sendall(data)

    def UpdateCodeTable(self, **kwargs):
        self.CodeTableRequest(10)
        self.SubMarketRequest(LYMK_FUTURE)


    def HandleCodeTable(self, **kwargs):
        message = kwargs['message']
        resp = RTS3_pb2.SecurityCodeResp()
        resp.ParseFromString(message['body'])
        self.queue.put([u'FuturesCodeTable', resp, kwargs['message']['head'][3]])

    def RequesetId(self):
        self.requesetId += 1
        return str(self.requesetId)

    def HandleFutures(self, **kwargs):
        message = kwargs['message']['body']
        market = RTS3_pb2.MarketDataFutures()
        market.ParseFromString(message)
        self.queue.put([u'FuturesMarket', market, kwargs['message']['head'][3]])
        if self.SignalFlag:
            code = self.marketSource.get_code_by_id(market.idnum)
            if code and self.signalDict.get(code, None):
                for function in self.signalDict[code].values():
                    function()

@Singleton.singleton
class RTS3_Index(Greenlet):
    def __init__(self):
        Greenlet.__init__(self)
        self.requesetId = 0
        self.config = ConfigFileData.Data()
        self.packTools = SocketTools.StructProtocol()
        self.queue = ThreadSafeSingletion.SafeQueue()
        self.RebuildConnection()
        self.LOG_CURR_TIME = time.clock()
        self.LOG_NEXT_TIME = int(self.config.get(u"Start.LogTimeInterval")) + int(self.LOG_CURR_TIME)
        self.SignalFlag = False
        self.signalDict = {}
        self.marketSource = IL.DataSource.Market.MarketSource()

    def RebuildConnection(self):
        while True:
            try:
                self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.sock.settimeout(5)
                self.sock.connect((self.config.get(u'market.RTS3Index.ip'), self.config.get(u'market.RTS3Index.port')))

            except:
                logging.warning(u"Market-Index:Socket连接失败, 等待5秒后重新尝试...")
                time.sleep(5)
                continue

            try:
                # 忽略连接成功后的市场代码
                header = self.Recv(self.packTools.getHeaderLen())
                self.Recv(self.packTools.GetBodyLen(header))
            except:
                pass

            try:
                self.UpdateCodeTable()
            except:
                logging.warning(u"与Index接口初次交互的时候，发生错误。重新连接并且尝试！")
                continue
            break

    def run(self):
        print u"[Start]Market-Index"
        switch = {
            LYMK_CODETABLE_ADD: self.UpdateCodeTable,
            LYMK_HEARTBEAT_REQ: self.Heart,
            LYMK_CODETABLE_RESP: self.HandleCodeTable,
            LYMK_INDEX: self.HandleIndex,
            LYMK_CODETABLE_CHANGE: self.RequestCodeTable
        }
        while True:
            self.LOG_CURR_TIME = int(time.clock())
            if int(self.LOG_CURR_TIME) > int(self.LOG_NEXT_TIME):
                self.LOG_NEXT_TIME = int(self.config.get(u"Start.LogTimeInterval")) + int(self.LOG_CURR_TIME)
                self.Heart()

            try:
                header = self.Recv(self.packTools.getHeaderLen())
                body = self.Recv(self.packTools.GetBodyLen(header))
                self.packTools.putData(header+body)
            except socket.error, e:
                if e.errno:
                    logging.warning(u"Index.recv 发生错误:{0}, 重新建立连接...".format(e))
                    self.RebuildConnection()
                continue
            except:
                logging.warning(u"Index:_run:发生未知错误。")
                exit(-1)

            while 1:
                data = self.packTools.getOnce()
                if data:
                    pType = data['head'][2]
                    try:
                        switch[int(pType)](message=data)
                    except:
                        logging.warning(u"Index处理行情包子类型：{0} 发生错误。".format(pType))
                else:
                    break

    def RequestCodeTable(self, **kwargs):
        message = kwargs['message']
        resp = RTS3_pb2.CodeTableChange()
        resp.ParseFromString(message['body'])
        self.CodeTableRequest(resp.exchid_flag)

    def OpenSignal(self):
        self.SignalFlag = True

    def CloseSignal(self):
        self.SignalFlag = False

    # speID 特征码
    def add_Signal(self, code, signalFunc, speID):
        if self.signalDict.get(code, None) is None:
            self.signalDict[code] = dict()
        self.signalDict[code][speID] = signalFunc

    def del_Signal(self, code, speID):
        try:
            self.signalDict[code].pop(speID)
        except:
            pass

    def CodeTableRequest(self, code):
        req = RTS3_pb2.CodeTableReq()
        req.exchid_flag = code
        req = req.SerializeToString()
        data = self.packTools.pack([len(req), base_pb2.SYS_QUOTATION, 0x0200, self.RequesetId()], req)
        self.sock.sendall(data)


    def Recv(self, Packlen):
        ret = str()
        while 1:
            recvBuf = self.sock.recv(Packlen-len(ret))
            if len(recvBuf) == Packlen-len(ret):
                ret += recvBuf
                break
            ret += recvBuf
        return ret

    def SubMarketRequest(self, sub):
        req = RTS3_pb2.MarketDataReqByMdType()
        req.sub_type = 1
        req.mk_type = sub
        req = req.SerializeToString()
        data = self.packTools.pack([len(req), base_pb2.SYS_QUOTATION, 0x0100, self.RequesetId()], req)
        self.sock.sendall(data)


    def Heart(self, **kwargs):
        data = self.packTools.pack([0, base_pb2.SYS_QUOTATION, base_pb2.CMD_HEARTBEAT_RESP, self.RequesetId()], '')
        self.sock.sendall(data)

    def UpdateCodeTable(self, **kwargs):
        self.SubMarketRequest(LYMK_INDEX)


    def HandleCodeTable(self, **kwargs):
        message = kwargs['message']
        resp = RTS3_pb2.SecurityCodeResp()
        resp.ParseFromString(message['body'])
        self.queue.put([u'StockCodeTable', resp, kwargs['message']['head'][3]])

    def HandleIndex(self, **kwargs):
        message = kwargs['message']['body']
        market = RTS3_pb2.IndexData()
        market.ParseFromString(message)
        self.queue.put([u'RTS3Index', market, kwargs['message']['head'][3]])
        if self.SignalFlag:
            code = self.marketSource.get_code_by_id(market.idnum)
            if code and self.signalDict.get(code, None):
                for function in self.signalDict[code].values():
                    function()


    def RequesetId(self):
        self.requesetId += 1
        return str(self.requesetId)
